﻿using System;
using System.CodeDom.Compiler;
using System.IO;

namespace FBGraph.ClientGenerator.CodeGen
{
    public class CodeGenWriter : IDisposable
    {
        public class IndentContainer : IDisposable
        {
            private CodeGenWriter _writer;

            public IndentContainer(CodeGenWriter writer)
            {
                this._writer = writer;
                this._writer.InnerWriter.Indent++;
            }

            void IDisposable.Dispose()
            {
                this._writer.InnerWriter.Indent--;
            }
        }

        public CodeGenWriter() : this(new MemoryStream()) { }

        public CodeGenWriter(Stream stream)
        {
            this.BaseStream = stream;
            this.InnerWriter = new IndentedTextWriter(new StreamWriter(stream));
        }

        public Stream BaseStream { get; private set; }
        public IndentedTextWriter InnerWriter { get; private set; }

        public void Write<T>(T obj)
            where T : ICodeGenObject
        {
            obj.Write(this);
        }

        public void Write(Char value)
        {
            this.InnerWriter.Write(value);
        }

        public void Write(String value)
        {
            this.InnerWriter.Write(value);
        }

        public void Write(String format, params Object[] args)
        {
            this.InnerWriter.Write(format, args);
        }

        public void Write(Object value)
        {
            var codeGenObj = value as ICodeGenObject;
            if (codeGenObj == null) this.InnerWriter.Write(value);
            else this.Write(codeGenObj);
        }

        public void WriteLine()
        {
            this.InnerWriter.WriteLine();
        }

        public void WriteLine(Char value)
        {
            this.InnerWriter.WriteLine(value);
        }

        public void WriteLine(String value)
        {
            this.InnerWriter.WriteLine(value);
        }

        public void WriteLine(String format, params Object[] args)
        {
            this.InnerWriter.WriteLine(format, args);
        }

        public void Write<T>(CodeGenObjectList<T> list)
        {
            list.Write(this);
        }

        public void Flush()
        {
            this.InnerWriter.Flush();
        }

        public IndentContainer Indent()
        {
            return new IndentContainer(this);
        }

        public override String ToString()
        {
            var position = this.BaseStream.Position;
            this.Flush();

            String value;
            using (var reader = new StreamReader(this.BaseStream))
            {
                this.BaseStream.Position = 0;
                value = reader.ReadToEnd();
                this.BaseStream.Position = position;
            }

            return value;
        }

        protected virtual void BeforeDispose() { }

        #region [ IDisposable Members ]

        void IDisposable.Dispose()
        {
            this.BeforeDispose();
            this.InnerWriter.Dispose();
        }

        #endregion
    }
}
